home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Software Money Savers / VirtualDub / Source / VirtualDub-1.7.7-src.7z / src / h / vd2 / system / thread.h < prev    next >
Encoding:
C/C++ Source or Header  |  2007-09-03  |  9.1 KB  |  311 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    System library component
  3. //    Copyright (C) 1998-2004 Avery Lee, All Rights Reserved.
  4. //
  5. //    Beginning with 1.6.0, the VirtualDub system library is licensed
  6. //    differently than the remainder of VirtualDub.  This particular file is
  7. //    thus licensed as follows (the "zlib" license):
  8. //
  9. //    This software is provided 'as-is', without any express or implied
  10. //    warranty.  In no event will the authors be held liable for any
  11. //    damages arising from the use of this software.
  12. //
  13. //    Permission is granted to anyone to use this software for any purpose,
  14. //    including commercial applications, and to alter it and redistribute it
  15. //    freely, subject to the following restrictions:
  16. //
  17. //    1.    The origin of this software must not be misrepresented; you must
  18. //        not claim that you wrote the original software. If you use this
  19. //        software in a product, an acknowledgment in the product
  20. //        documentation would be appreciated but is not required.
  21. //    2.    Altered source versions must be plainly marked as such, and must
  22. //        not be misrepresented as being the original software.
  23. //    3.    This notice may not be removed or altered from any source
  24. //        distribution.
  25.  
  26. #ifndef f_VD2_SYSTEM_THREAD_H
  27. #define f_VD2_SYSTEM_THREAD_H
  28.  
  29. #ifdef _MSC_VER
  30.     #pragma once
  31. #endif
  32.  
  33. #include <vd2/system/vdtypes.h>
  34. #include <vd2/system/atomic.h>
  35.  
  36. typedef void *VDThreadHandle;
  37. typedef unsigned VDThreadID;
  38.  
  39. struct _RTL_CRITICAL_SECTION;
  40.  
  41. extern "C" void __declspec(dllimport) __stdcall InitializeCriticalSection(_RTL_CRITICAL_SECTION *lpCriticalSection);
  42. extern "C" void __declspec(dllimport) __stdcall LeaveCriticalSection(_RTL_CRITICAL_SECTION *lpCriticalSection);
  43. extern "C" void __declspec(dllimport) __stdcall EnterCriticalSection(_RTL_CRITICAL_SECTION *lpCriticalSection);
  44. extern "C" void __declspec(dllimport) __stdcall DeleteCriticalSection(_RTL_CRITICAL_SECTION *lpCriticalSection);
  45.  
  46. VDThreadID VDGetCurrentThreadID();
  47.  
  48. void VDSetThreadDebugName(VDThreadID tid, const char *name);
  49.  
  50. ///////////////////////////////////////////////////////////////////////////
  51. //
  52. //    VDThread
  53. //
  54. //    VDThread is a quick way to portably create threads -- to use it,
  55. //    derive a subclass from it that implements the ThreadRun() function.
  56. //
  57. //    Win32 notes:
  58. //
  59. //    The thread startup code will attempt to notify the VC++ debugger of
  60. //    the debug name of the thread.  Only the first 9 characters are used
  61. //    by Visual C 6.0; Visual Studio .NET will accept a few dozen.
  62. //
  63. //    VDThread objects must not be WaitThread()ed or destructed from a
  64. //    DllMain() function, TLS callback for an executable, or static
  65. //    destructor unless the thread has been detached from the object.
  66. //  The reason is that Win32 serializes calls to DllMain() functions.
  67. //  If you attempt to do so, you will cause a deadlock when Win32
  68. //  attempts to fire thread detach notifications.
  69. //
  70. ///////////////////////////////////////////////////////////////////////////
  71.  
  72. class VDThread {
  73. public:
  74.     VDThread(const char *pszDebugName = NULL);    // NOTE: pszDebugName must have static duration
  75.     ~VDThread() throw();
  76.  
  77.     // external functions
  78.  
  79.     bool ThreadStart();                            // start thread
  80.     void ThreadDetach();                        // detach thread (wait() won't be called)
  81.     void ThreadWait();                            // wait for thread to finish
  82.  
  83.     bool isThreadActive();
  84.  
  85.     bool isThreadAttached() const {                // NOTE: Will return true if thread started, even if thread has since exited
  86.         return mhThread != 0;
  87.     }
  88.  
  89.     VDThreadHandle getThreadHandle() const {    // get handle to thread (Win32: HANDLE)
  90.         return mhThread;
  91.     }
  92.  
  93.     VDThreadID getThreadID() const {            // get ID of thread (Win32: DWORD)
  94.         return mThreadID;
  95.     }
  96.  
  97.     void *ThreadLocation() const;                // retrieve current EIP of thread (use only for debug purposes -- may not return reliable information on syscall, etc.)
  98.  
  99.     // thread-local functions
  100.  
  101.     virtual void ThreadRun() = 0;                // thread, come to life
  102.     void ThreadFinish();                        // exit thread
  103.  
  104. private:
  105.     static unsigned __stdcall StaticThreadStart(void *pThis);
  106.  
  107.     const char *mpszDebugName;
  108.     VDThreadHandle    mhThread;
  109.     VDThreadID        mThreadID;
  110. };
  111.  
  112. ///////////////////////////////////////////////////////////////////////////
  113.  
  114. class VDCriticalSection {
  115. private:
  116.     struct CritSec {                // This is a clone of CRITICAL_SECTION.
  117.         void    *DebugInfo;
  118.         sint32    LockCount;
  119.         sint32    RecursionCount;
  120.         void    *OwningThread;
  121.         void    *LockSemaphore;
  122.         uint32    SpinCount;
  123.     } csect;
  124.  
  125.     VDCriticalSection(const VDCriticalSection&);
  126.     const VDCriticalSection& operator=(const VDCriticalSection&);
  127.     static void StructCheck();
  128. public:
  129.     class AutoLock {
  130.     private:
  131.         VDCriticalSection& cs;
  132.     public:
  133.         AutoLock(VDCriticalSection& csect) : cs(csect) { cs.Lock(); }
  134.         ~AutoLock() { cs.Unlock(); }
  135.  
  136.         inline operator bool() const { return false; }
  137.     };
  138.  
  139.     VDCriticalSection() {
  140.         InitializeCriticalSection((_RTL_CRITICAL_SECTION *)&csect);
  141.     }
  142.  
  143.     ~VDCriticalSection() {
  144.         DeleteCriticalSection((_RTL_CRITICAL_SECTION *)&csect);
  145.     }
  146.  
  147.     void operator++() {
  148.         EnterCriticalSection((_RTL_CRITICAL_SECTION *)&csect);
  149.     }
  150.  
  151.     void operator--() {
  152.         LeaveCriticalSection((_RTL_CRITICAL_SECTION *)&csect);
  153.     }
  154.  
  155.     void Lock() {
  156.         EnterCriticalSection((_RTL_CRITICAL_SECTION *)&csect);
  157.     }
  158.  
  159.     void Unlock() {
  160.         LeaveCriticalSection((_RTL_CRITICAL_SECTION *)&csect);
  161.     }
  162. };
  163.  
  164. // 'vdsynchronized' keyword
  165. //
  166. // The vdsynchronized(lock) keyword emulates Java's 'synchronized' keyword, which
  167. // protects the following statement or block from race conditions by obtaining a
  168. // lock during its execution:
  169. //
  170. //        vdsynchronized(list_lock) {
  171. //            mList.pop_back();
  172. //            if (mList.empty())
  173. //                return false;
  174. //        }
  175. //
  176. // The construct is exception safe and will release the lock even if a return,
  177. // continue, break, or thrown exception exits the block.  However, hardware
  178. // exceptions (access violations) may not work due to synchronous model
  179. // exception handling.
  180. //
  181. // There are two Visual C++ bugs we need to work around here (both are in VC6 and VC7).
  182. //
  183. // 1) Declaring an object with a non-trivial destructor in a switch() condition
  184. //    causes a C1001 INTERNAL COMPILER ERROR.
  185. //
  186. // 2) Using __LINE__ in a macro expanded in a function with Edit and Continue (/ZI)
  187. //    breaks the preprocessor (KB article Q199057).  Shame, too, because without it
  188. //    all the autolocks look the same.
  189.  
  190. #define vdsynchronized2(lock) if(VDCriticalSection::AutoLock vd__lock=(lock))VDNEVERHERE;else
  191. #define vdsynchronized1(lock) vdsynchronized2(lock)
  192. #define vdsynchronized(lock) vdsynchronized1(lock)
  193.  
  194. ///////////////////////////////////////////////////////////////////////////
  195.  
  196. class VDSignalBase {
  197. protected:
  198.     void *hEvent;
  199.  
  200. public:
  201.     ~VDSignalBase();
  202.  
  203.     void signal();
  204.     bool check();
  205.     void wait();
  206.     int wait(VDSignalBase *second);
  207.     int wait(VDSignalBase *second, VDSignalBase *third);
  208.     void *getHandle() { return hEvent; }
  209.  
  210.     void operator()() { signal(); }
  211. };
  212.  
  213. class VDSignal : public VDSignalBase {
  214.     VDSignal(const VDSignal&);
  215.     VDSignal& operator=(const VDSignal&);
  216. public:
  217.     VDSignal();
  218. };
  219.  
  220. class VDSignalPersistent : public VDSignalBase {
  221.     VDSignalPersistent(const VDSignalPersistent&);
  222.     VDSignalPersistent& operator=(const VDSignalPersistent&);
  223. public:
  224.     VDSignalPersistent();
  225.  
  226.     void unsignal();
  227. };
  228.  
  229. ///////////////////////////////////////////////////////////////////////////
  230.  
  231. class VDSemaphore {
  232.     VDAtomicInt mValue;
  233.     VDSignal    mSignalNotEmpty;
  234.  
  235.     VDSemaphore(const VDSemaphore&);
  236.     VDSemaphore& operator=(const VDSemaphore&);
  237. public:
  238.     VDSemaphore() : mValue(0) {}
  239.     explicit VDSemaphore(int initial) : mValue(initial) {}
  240.  
  241.     void reset(int count) {
  242.         mValue = count;
  243.     }
  244.  
  245.     // I'm not using P and V.  No way.
  246.  
  247.     void operator++() {
  248.         if (!mValue.postinc())
  249.             mSignalNotEmpty();
  250.     }
  251.  
  252.     void operator--() {
  253.         while(mValue.postdec()<=0) {
  254.             // Here's where it gets tricky.  Any number of threads may
  255.             // have gotten to this point and done a down(), so the result
  256.             // may any negative value.  What we do now is increment the
  257.             // value back up before we block.  However, our decrementing
  258.             // the variable may have prevented the first up() from
  259.             // signalling.  This is indicated by a restore above zero,
  260.             // in which case we signal instead of wait.
  261.  
  262.             if (!mValue.postinc()) {
  263.                 mSignalNotEmpty();
  264.                 continue;
  265.             }
  266.  
  267.             mSignalNotEmpty.wait();
  268.         }
  269.     }
  270. };
  271.  
  272. class VDLockedSemaphore {
  273.     int            mValue;
  274.     VDSignal    mSignalNotEmpty;
  275.  
  276.     VDLockedSemaphore(const VDLockedSemaphore&);
  277.     VDLockedSemaphore& operator=(const VDLockedSemaphore&);
  278. public:
  279.     VDLockedSemaphore() : mValue(0) {}
  280.     explicit VDLockedSemaphore(int initial) : mValue(initial) {}
  281.  
  282.     int count() const { return mValue; }
  283.  
  284.     void reset(int count) {
  285.         mValue = count;
  286.     }
  287.  
  288.     bool post(VDCriticalSection&, int threshold = 0) {
  289.         if (threshold == mValue++) {
  290.             mSignalNotEmpty();
  291.             return true;
  292.         }
  293.  
  294.         return false;
  295.     }
  296.  
  297.     bool wait(VDCriticalSection& csect, int threshold = 0) {
  298.         // This is a bit easier than the other case.
  299.         while(!mValue) {
  300.             csect.Unlock();
  301.             mSignalNotEmpty.wait();
  302.             csect.Lock();
  303.         }
  304.  
  305.         return threshold == --mValue;
  306.     }
  307.  
  308. };
  309.  
  310. #endif
  311.